1   /*
2    * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.security.auth;
27  
28  import java.io.*;
29  import java.lang.RuntimePermission;
30  import java.lang.reflect.*;
31  import java.net.MalformedURLException;
32  import java.net.URL;
33  import java.util.*;
34  
35  import java.security.AccessController;
36  import java.security.CodeSource;
37  import java.security.KeyStore;
38  import java.security.KeyStoreException;
39  import java.security.Permission;
40  import java.security.Permissions;
41  import java.security.PermissionCollection;
42  import java.security.Principal;
43  import java.security.UnresolvedPermission;
44  import java.security.Security;
45  import java.security.cert.Certificate;
46  import java.security.cert.X509Certificate;
47  
48  import javax.security.auth.Subject;
49  import javax.security.auth.PrivateCredentialPermission;
50  
51  import sun.security.util.PropertyExpander;
52  
53  /**
54   * This class represents a default implementation for
55   * <code>javax.security.auth.Policy</code>.
56   *
57   * <p> This object stores the policy for entire Java runtime,
58   * and is the amalgamation of multiple static policy
59   * configurations that resides in files.
60   * The algorithm for locating the policy file(s) and reading their
61   * information into this <code>Policy</code> object is:
62   *
63   * <ol>
64   * <li>
65   *   Loop through the <code>java.security.Security</code> properties,
66   *   <i>auth.policy.url.1</i>, <i>auth.policy.url.2</i>, ...,
67   *   <i>auth.policy.url.X</i>".  These properties are set
68   *   in the Java security properties file, which is located in the file named
69   *   &lt;JAVA_HOME&gt;/lib/security/java.security.
70   *   &lt;JAVA_HOME&gt; refers to the value of the java.home system property,
71   *   and specifies the directory where the JRE is installed.
72   *   Each property value specifies a <code>URL</code> pointing to a
73   *   policy file to be loaded.  Read in and load each policy.
74   *
75   * <li>
76   *   The <code>java.lang.System</code> property <i>java.security.auth.policy</i>
77   *   may also be set to a <code>URL</code> pointing to another policy file
78   *   (which is the case when a user uses the -D switch at runtime).
79   *   If this property is defined, and its use is allowed by the
80   *   security property file (the Security property,
81   *   <i>policy.allowSystemProperty</i> is set to <i>true</i>),
82   *   also load that policy.
83   *
84   * <li>
85   *   If the <i>java.security.auth.policy</i> property is defined using
86   *   "==" (rather than "="), then ignore all other specified
87   *   policies and only load this policy.
88   * </ol>
89   *
90   * Each policy file consists of one or more grant entries, each of
91   * which consists of a number of permission entries.
92   *
93   * <pre>
94   *   grant signedBy "<b>alias</b>", codeBase "<b>URL</b>",
95   *         principal <b>principalClass</b> "<b>principalName</b>",
96   *         principal <b>principalClass</b> "<b>principalName</b>",
97   *         ... {
98   *
99   *     permission <b>Type</b> "<b>name</b> "<b>action</b>",
100  *         signedBy "<b>alias</b>";
101  *     permission <b>Type</b> "<b>name</b> "<b>action</b>",
102  *         signedBy "<b>alias</b>";
103  *     ....
104  *   };
105  * </pre>
106  *
107  * All non-bold items above must appear as is (although case
108  * doesn't matter and some are optional, as noted below).
109  * Italicized items represent variable values.
110  *
111  * <p> A grant entry must begin with the word <code>grant</code>.
112  * The <code>signedBy</code> and <code>codeBase</code>
113  * name/value pairs are optional.
114  * If they are not present, then any signer (including unsigned code)
115  * will match, and any codeBase will match.  Note that the
116  * <code>principal</code> name/value pair is not optional.
117  * This <code>Policy</code> implementation only permits
118  * Principal-based grant entries.  Note that the <i>principalClass</i>
119  * may be set to the wildcard value, *, which allows it to match
120  * any <code>Principal</code> class.  In addition, the <i>principalName</i>
121  * may also be set to the wildcard value, *, allowing it to match
122  * any <code>Principal</code> name.  When setting the <i>principalName</i>
123  * to the *, do not surround the * with quotes.
124  *
125  * <p> A permission entry must begin with the word <code>permission</code>.
126  * The word <code><i>Type</i></code> in the template above is
127  * a specific permission type, such as <code>java.io.FilePermission</code>
128  * or <code>java.lang.RuntimePermission</code>.
129  *
130  * <p> The "<i>action</i>" is required for
131  * many permission types, such as <code>java.io.FilePermission</code>
132  * (where it specifies what type of file access that is permitted).
133  * It is not required for categories such as
134  * <code>java.lang.RuntimePermission</code>
135  * where it is not necessary - you either have the
136  * permission specified by the <code>"<i>name</i>"</code>
137  * value following the type name or you don't.
138  *
139  * <p> The <code>signedBy</code> name/value pair for a permission entry
140  * is optional. If present, it indicates a signed permission. That is,
141  * the permission class itself must be signed by the given alias in
142  * order for it to be granted. For example,
143  * suppose you have the following grant entry:
144  *
145  * <pre>
146  *   grant principal foo.com.Principal "Duke" {
147  *     permission Foo "foobar", signedBy "FooSoft";
148  *   }
149  * </pre>
150  *
151  * <p> Then this permission of type <i>Foo</i> is granted if the
152  * <code>Foo.class</code> permission has been signed by the
153  * "FooSoft" alias, or if <code>Foo.class</code> is a
154  * system class (i.e., is found on the CLASSPATH).
155  *
156  * <p> Items that appear in an entry must appear in the specified order
157  * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
158  * "<i>action</i>"). An entry is terminated with a semicolon.
159  *
160  * <p> Case is unimportant for the identifiers (<code>permission</code>,
161  * <code>signedBy</code>, <code>codeBase</code>, etc.) but is
162  * significant for the <i>Type</i>
163  * or for any string that is passed in as a value. <p>
164  *
165  * <p> An example of two entries in a policy configuration file is
166  * <pre>
167  *   // if the code is comes from "foo.com" and is running as "Duke",
168  *   // grant it read/write to all files in /tmp.
169  *
170  *   grant codeBase "foo.com", principal foo.com.Principal "Duke" {
171  *              permission java.io.FilePermission "/tmp/*", "read,write";
172  *   };
173  *
174  *   // grant any code running as "Duke" permission to read
175  *   // the "java.vendor" Property.
176  *
177  *   grant principal foo.com.Principal "Duke" {
178  *         permission java.util.PropertyPermission "java.vendor";
179  * </pre>
180  *
181  * <p> This <code>Policy</code> implementation supports
182  * special handling for PrivateCredentialPermissions.
183  * If a grant entry is configured with a
184  * <code>PrivateCredentialPermission</code>,
185  * and the "Principal Class/Principal Name" for that
186  * <code>PrivateCredentialPermission</code> is "self",
187  * then the entry grants the specified <code>Subject</code> permission to
188  * access its own private Credential.  For example,
189  * the following grants the <code>Subject</code> "Duke"
190  * access to its own a.b.Credential.
191  *
192  * <pre>
193  *   grant principal foo.com.Principal "Duke" {
194  *      permission javax.security.auth.PrivateCredentialPermission
195  *              "a.b.Credential self",
196  *              "read";
197  *    };
198  * </pre>
199  *
200  * The following grants the <code>Subject</code> "Duke"
201  * access to all of its own private Credentials:
202  *
203  * <pre>
204  *   grant principal foo.com.Principal "Duke" {
205  *      permission javax.security.auth.PrivateCredentialPermission
206  *              "* self",
207  *              "read";
208  *    };
209  * </pre>
210  *
211  * The following grants all Subjects authenticated as a
212  * <code>SolarisPrincipal</code> (regardless of their respective names)
213  * permission to access their own private Credentials:
214  *
215  * <pre>
216  *   grant principal com.sun.security.auth.SolarisPrincipal * {
217  *      permission javax.security.auth.PrivateCredentialPermission
218  *              "* self",
219  *              "read";
220  *    };
221  * </pre>
222  *
223  * The following grants all Subjects permission to access their own
224  * private Credentials:
225  *
226  * <pre>
227  *   grant principal * * {
228  *      permission javax.security.auth.PrivateCredentialPermission
229  *              "* self",
230  *              "read";
231  *    };
232  * </pre>
233 
234  * @deprecated As of JDK&nbsp;1.4, replaced by
235  *             <code>sun.security.provider.PolicyFile</code>.
236  *             This class is entirely deprecated.
237  *
238  * @see java.security.CodeSource
239  * @see java.security.Permissions
240  * @see java.security.ProtectionDomain
241  */
242 @Deprecated
243 public class PolicyFile extends javax.security.auth.Policy {
244 
245     static final java.util.ResourceBundle rb =
246         java.security.AccessController.doPrivileged
247         (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
248             public java.util.ResourceBundle run() {
249                 return (java.util.ResourceBundle.getBundle
250                         ("sun.security.util.AuthResources"));
251             }
252         });
253     // needs to be package private
254 
255     private static final sun.security.util.Debug debug =
256         sun.security.util.Debug.getInstance("policy", "\t[Auth Policy]");
257 
258     private static final String AUTH_POLICY = "java.security.auth.policy";
259     private static final String SECURITY_MANAGER = "java.security.manager";
260     private static final String AUTH_POLICY_URL = "auth.policy.url.";
261 
262     private Vector<PolicyEntry> policyEntries;
263     private Hashtable aliasMapping;
264 
265     private boolean initialized = false;
266 
267     private boolean expandProperties = true;
268     private boolean ignoreIdentityScope = true;
269 
270     // for use with the reflection API
271 
272     private static final Class[] PARAMS = { String.class, String.class};
273 
274     /**
275      * Initializes the Policy object and reads the default policy
276      * configuration file(s) into the Policy object.
277      */
278     public PolicyFile() {
279         // initialize Policy if either the AUTH_POLICY or
280         // SECURITY_MANAGER properties are set
281         String prop = System.getProperty(AUTH_POLICY);
282 
283         if (prop == null) {
284             prop = System.getProperty(SECURITY_MANAGER);
285         }
286         if (prop != null)
287             init();
288     }
289 
290     private synchronized void init() {
291 
292         if (initialized)
293             return;
294 
295         policyEntries = new Vector<PolicyEntry>();
296         aliasMapping = new Hashtable(11);
297 
298         initPolicyFile();
299         initialized = true;
300     }
301 
302     /**
303      * Refreshes the policy object by re-reading all the policy files.
304      *
305      * <p>
306      *
307      * @exception SecurityException if the caller doesn't have permission
308      *          to refresh the <code>Policy</code>.
309      */
310     public synchronized void refresh()
311     {
312 
313         java.lang.SecurityManager sm = System.getSecurityManager();
314         if (sm != null) {
315             sm.checkPermission(new javax.security.auth.AuthPermission
316                                 ("refreshPolicy"));
317         }
318 
319         // XXX
320         //
321         // 1)   if code instantiates PolicyFile directly, then it will need
322         //      all the permissions required for the PolicyFile initialization
323         // 2)   if code calls Policy.getPolicy, then it simply needs
324         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
325         //      implementation instantiates PolicyFile in a doPrivileged block
326         // 3)   if after instantiating a Policy (either via #1 or #2),
327         //      code calls refresh, it simply needs
328         //      AuthPermission(refreshPolicy).  then PolicyFile wraps
329         //      the refresh in a doPrivileged block.
330         initialized = false;
331         java.security.AccessController.doPrivileged
332             (new java.security.PrivilegedAction<Void>() {
333             public Void run() {
334                 init();
335                 return null;
336             }
337         });
338     }
339 
340     private KeyStore initKeyStore(URL policyUrl, String keyStoreName,
341                                   String keyStoreType) {
342         if (keyStoreName != null) {
343             try {
344                 /*
345                  * location of keystore is specified as absolute URL in policy
346                  * file, or is relative to URL of policy file
347                  */
348                 URL keyStoreUrl = null;
349                 try {
350                     keyStoreUrl = new URL(keyStoreName);
351                     // absolute URL
352                 } catch (java.net.MalformedURLException e) {
353                     // relative URL
354                     keyStoreUrl = new URL(policyUrl, keyStoreName);
355                 }
356 
357                 if (debug != null) {
358                     debug.println("reading keystore"+keyStoreUrl);
359                 }
360 
361                 InputStream inStream =
362                     new BufferedInputStream(getInputStream(keyStoreUrl));
363 
364                 KeyStore ks;
365                 if (keyStoreType != null)
366                     ks = KeyStore.getInstance(keyStoreType);
367                 else
368                     ks = KeyStore.getInstance(KeyStore.getDefaultType());
369                 ks.load(inStream, null);
370                 inStream.close();
371                 return ks;
372             } catch (Exception e) {
373                 // ignore, treat it like we have no keystore
374                 if (debug != null) {
375                     e.printStackTrace();
376                 }
377                 return null;
378             }
379         }
380         return null;
381     }
382 
383     private void initPolicyFile() {
384 
385         String prop = Security.getProperty("policy.expandProperties");
386 
387         if (prop != null) expandProperties = prop.equalsIgnoreCase("true");
388 
389         String iscp = Security.getProperty("policy.ignoreIdentityScope");
390 
391         if (iscp != null) ignoreIdentityScope = iscp.equalsIgnoreCase("true");
392 
393         String allowSys  = Security.getProperty("policy.allowSystemProperty");
394 
395         if ((allowSys!=null) && allowSys.equalsIgnoreCase("true")) {
396 
397             String extra_policy = System.getProperty(AUTH_POLICY);
398             if (extra_policy != null) {
399                 boolean overrideAll = false;
400                 if (extra_policy.startsWith("=")) {
401                     overrideAll = true;
402                     extra_policy = extra_policy.substring(1);
403                 }
404                 try {
405                     extra_policy = PropertyExpander.expand(extra_policy);
406                     URL policyURL;;
407                     File policyFile = new File(extra_policy);
408                     if (policyFile.exists()) {
409                         policyURL =
410                             new URL("file:" + policyFile.getCanonicalPath());
411                     } else {
412                         policyURL = new URL(extra_policy);
413                     }
414                     if (debug != null)
415                         debug.println("reading "+policyURL);
416                     init(policyURL);
417                 } catch (Exception e) {
418                     // ignore.
419                     if (debug != null) {
420                         debug.println("caught exception: "+e);
421                     }
422 
423                 }
424                 if (overrideAll) {
425                     if (debug != null) {
426                         debug.println("overriding other policies!");
427                     }
428                     return;
429                 }
430             }
431         }
432 
433         int n = 1;
434         boolean loaded_one = false;
435         String policy_url;
436 
437         while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) {
438             try {
439                 policy_url = PropertyExpander.expand(policy_url).replace
440                                                 (File.separatorChar, '/');
441                 if (debug != null)
442                     debug.println("reading "+policy_url);
443                 init(new URL(policy_url));
444                 loaded_one = true;
445             } catch (Exception e) {
446                 if (debug != null) {
447                     debug.println("error reading policy "+e);
448                     e.printStackTrace();
449                 }
450                 // ignore that policy
451             }
452             n++;
453         }
454 
455         if (loaded_one == false) {
456             // do not load a static policy
457         }
458     }
459 
460     /**
461      * Checks public key. If it is marked as trusted in
462      * the identity database, add it to the policy
463      * with the AllPermission.
464      */
465     private boolean checkForTrustedIdentity(final Certificate cert) {
466         // XXX  JAAS has no way to access the SUN package.
467         //      we'll add this back in when JAAS goes into core.
468         return false;
469     }
470 
471     /**
472      * Reads a policy configuration into the Policy object using a
473      * Reader object.
474      *
475      * @param policyFile the policy Reader object.
476      */
477     private void init(URL policy) {
478         PolicyParser pp = new PolicyParser(expandProperties);
479         try {
480             InputStreamReader isr
481                 = new InputStreamReader(getInputStream(policy));
482             pp.read(isr);
483             isr.close();
484             KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(),
485                                              pp.getKeyStoreType());
486             Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
487             while (enum_.hasMoreElements()) {
488                 PolicyParser.GrantEntry ge = enum_.nextElement();
489                 addGrantEntry(ge, keyStore);
490             }
491         } catch (PolicyParser.ParsingException pe) {
492             System.err.println(AUTH_POLICY +
493                                 rb.getString(".error.parsing.") + policy);
494             System.err.println(AUTH_POLICY +
495                                 rb.getString("COLON") +
496                                 pe.getMessage());
497             if (debug != null)
498                 pe.printStackTrace();
499 
500         } catch (Exception e) {
501             if (debug != null) {
502                 debug.println("error parsing "+policy);
503                 debug.println(e.toString());
504                 e.printStackTrace();
505             }
506         }
507     }
508 
509     /*
510      * Fast path reading from file urls in order to avoid calling
511      * FileURLConnection.connect() which can be quite slow the first time
512      * it is called. We really should clean up FileURLConnection so that
513      * this is not a problem but in the meantime this fix helps reduce
514      * start up time noticeably for the new launcher. -- DAC
515      */
516     private InputStream getInputStream(URL url) throws IOException {
517         if ("file".equals(url.getProtocol())) {
518             String path = url.getFile().replace('/', File.separatorChar);
519             return new FileInputStream(path);
520         } else {
521             return url.openStream();
522         }
523     }
524 
525     /**
526      * Given a PermissionEntry, create a codeSource.
527      *
528      * @return null if signedBy alias is not recognized
529      */
530     CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore)
531         throws java.net.MalformedURLException
532     {
533         Certificate[] certs = null;
534         if (ge.signedBy != null) {
535             certs = getCertificates(keyStore, ge.signedBy);
536             if (certs == null) {
537                 // we don't have a key for this alias,
538                 // just return
539                 if (debug != null) {
540                     debug.println(" no certs for alias " +
541                                        ge.signedBy + ", ignoring.");
542                 }
543                 return null;
544             }
545         }
546 
547         URL location;
548 
549         if (ge.codeBase != null)
550             location = new URL(ge.codeBase);
551         else
552             location = null;
553 
554         if (ge.principals == null || ge.principals.size() == 0) {
555             return (canonicalizeCodebase
556                         (new CodeSource(location, certs),
557                         false));
558         } else {
559             return (canonicalizeCodebase
560                 (new SubjectCodeSource(null, ge.principals, location, certs),
561                 false));
562         }
563     }
564 
565     /**
566      * Add one policy entry to the vector.
567      */
568     private void addGrantEntry(PolicyParser.GrantEntry ge,
569                                KeyStore keyStore) {
570 
571         if (debug != null) {
572             debug.println("Adding policy entry: ");
573             debug.println("  signedBy " + ge.signedBy);
574             debug.println("  codeBase " + ge.codeBase);
575             if (ge.principals != null && ge.principals.size() > 0) {
576                 ListIterator<PolicyParser.PrincipalEntry> li =
577                                                 ge.principals.listIterator();
578                 while (li.hasNext()) {
579                     PolicyParser.PrincipalEntry pppe = li.next();
580                     debug.println("  " + pppe.principalClass +
581                                         " " + pppe.principalName);
582                 }
583             }
584             debug.println();
585         }
586 
587         try {
588             CodeSource codesource = getCodeSource(ge, keyStore);
589             // skip if signedBy alias was unknown...
590             if (codesource == null) return;
591 
592             PolicyEntry entry = new PolicyEntry(codesource);
593             Enumeration<PolicyParser.PermissionEntry> enum_ =
594                                                 ge.permissionElements();
595             while (enum_.hasMoreElements()) {
596                 PolicyParser.PermissionEntry pe = enum_.nextElement();
597                 try {
598                     // XXX special case PrivateCredentialPermission-SELF
599                     Permission perm;
600                     if (pe.permission.equals
601                         ("javax.security.auth.PrivateCredentialPermission") &&
602                         pe.name.endsWith(" self")) {
603                         perm = getInstance(pe.permission,
604                                          pe.name + " \"self\"",
605                                          pe.action);
606                     } else {
607                         perm = getInstance(pe.permission,
608                                          pe.name,
609                                          pe.action);
610                     }
611                     entry.add(perm);
612                     if (debug != null) {
613                         debug.println("  "+perm);
614                     }
615                 } catch (ClassNotFoundException cnfe) {
616                     Certificate certs[];
617                     if (pe.signedBy != null)
618                         certs = getCertificates(keyStore, pe.signedBy);
619                     else
620                         certs = null;
621 
622                     // only add if we had no signer or we had a
623                     // a signer and found the keys for it.
624                     if (certs != null || pe.signedBy == null) {
625                             Permission perm = new UnresolvedPermission(
626                                              pe.permission,
627                                              pe.name,
628                                              pe.action,
629                                              certs);
630                             entry.add(perm);
631                             if (debug != null) {
632                                 debug.println("  "+perm);
633                             }
634                     }
635                 } catch (java.lang.reflect.InvocationTargetException ite) {
636                     System.err.println
637                         (AUTH_POLICY +
638                         rb.getString(".error.adding.Permission.") +
639                         pe.permission +
640                         rb.getString("SPACE") +
641                         ite.getTargetException());
642                 } catch (Exception e) {
643                     System.err.println
644                         (AUTH_POLICY +
645                         rb.getString(".error.adding.Permission.") +
646                         pe.permission +
647                         rb.getString("SPACE") +
648                         e);
649                 }
650             }
651             policyEntries.addElement(entry);
652         } catch (Exception e) {
653             System.err.println
654                 (AUTH_POLICY +
655                 rb.getString(".error.adding.Entry.") +
656                 ge +
657                 rb.getString("SPACE") +
658                 e);
659         }
660 
661         if (debug != null)
662             debug.println();
663     }
664 
665     /**
666      * Returns a new Permission object of the given Type. The Permission is
667      * created by getting the
668      * Class object using the <code>Class.forName</code> method, and using
669      * the reflection API to invoke the (String name, String actions)
670      * constructor on the
671      * object.
672      *
673      * @param type the type of Permission being created.
674      * @param name the name of the Permission being created.
675      * @param actions the actions of the Permission being created.
676      *
677      * @exception  ClassNotFoundException  if the particular Permission
678      *             class could not be found.
679      *
680      * @exception  IllegalAccessException  if the class or initializer is
681      *               not accessible.
682      *
683      * @exception  InstantiationException  if getInstance tries to
684      *               instantiate an abstract class or an interface, or if the
685      *               instantiation fails for some other reason.
686      *
687      * @exception  NoSuchMethodException if the (String, String) constructor
688      *               is not found.
689      *
690      * @exception  InvocationTargetException if the underlying Permission
691      *               constructor throws an exception.
692      *
693      */
694 
695     private static final Permission getInstance(String type,
696                                     String name,
697                                     String actions)
698         throws ClassNotFoundException,
699                InstantiationException,
700                IllegalAccessException,
701                NoSuchMethodException,
702                InvocationTargetException
703     {
704         //XXX we might want to keep a hash of created factories...
705         Class pc = Class.forName(type);
706         Constructor c = pc.getConstructor(PARAMS);
707         return (Permission) c.newInstance(new Object[] { name, actions });
708     }
709 
710     /**
711      * Fetch all certs associated with this alias.
712      */
713     Certificate[] getCertificates(
714                                     KeyStore keyStore, String aliases) {
715 
716         Vector<Certificate> vcerts = null;
717 
718         StringTokenizer st = new StringTokenizer(aliases, ",");
719         int n = 0;
720 
721         while (st.hasMoreTokens()) {
722             String alias = st.nextToken().trim();
723             n++;
724             Certificate cert = null;
725             //See if this alias's cert has already been cached
726             cert = (Certificate) aliasMapping.get(alias);
727             if (cert == null && keyStore != null) {
728 
729                 try {
730                     cert = keyStore.getCertificate(alias);
731                 } catch (KeyStoreException kse) {
732                     // never happens, because keystore has already been loaded
733                     // when we call this
734                 }
735                 if (cert != null) {
736                     aliasMapping.put(alias, cert);
737                     aliasMapping.put(cert, alias);
738                 }
739             }
740 
741             if (cert != null) {
742                 if (vcerts == null)
743                     vcerts = new Vector<Certificate>();
744                 vcerts.addElement(cert);
745             }
746         }
747 
748         // make sure n == vcerts.size, since we are doing a logical *and*
749         if (vcerts != null && n == vcerts.size()) {
750             Certificate[] certs = new Certificate[vcerts.size()];
751             vcerts.copyInto(certs);
752             return certs;
753         } else {
754             return null;
755         }
756     }
757 
758     /**
759      * Enumerate all the entries in the global policy object.
760      * This method is used by policy admin tools.   The tools
761      * should use the Enumeration methods on the returned object
762      * to fetch the elements sequentially.
763      */
764     private final synchronized Enumeration<PolicyEntry> elements(){
765         return policyEntries.elements();
766     }
767 
768     /**
769      * Examines this <code>Policy</code> and returns the Permissions granted
770      * to the specified <code>Subject</code> and <code>CodeSource</code>.
771      *
772      * <p> Permissions for a particular <i>grant</i> entry are returned
773      * if the <code>CodeSource</code> constructed using the codebase and
774      * signedby values specified in the entry <code>implies</code>
775      * the <code>CodeSource</code> provided to this method, and if the
776      * <code>Subject</code> provided to this method contains all of the
777      * Principals specified in the entry.
778      *
779      * <p> The <code>Subject</code> provided to this method contains all
780      * of the Principals specified in the entry if, for each
781      * <code>Principal</code>, "P1", specified in the <i>grant</i> entry
782      * one of the following two conditions is met:
783      *
784      * <p>
785      * <ol>
786      * <li> the <code>Subject</code> has a
787      *      <code>Principal</code>, "P2", where
788      *      <code>P2.getClass().getName()</code> equals the
789      *      P1's class name, and where
790      *      <code>P2.getName()</code> equals the P1's name.
791      *
792      * <li> P1 implements
793      *      <code>com.sun.security.auth.PrincipalComparator</code>,
794      *      and <code>P1.implies</code> the provided <code>Subject</code>.
795      * </ol>
796      *
797      * <p> Note that this <code>Policy</code> implementation has
798      * special handling for PrivateCredentialPermissions.
799      * When this method encounters a <code>PrivateCredentialPermission</code>
800      * which specifies "self" as the <code>Principal</code> class and name,
801      * it does not add that <code>Permission</code> to the returned
802      * <code>PermissionCollection</code>.  Instead, it builds
803      * a new <code>PrivateCredentialPermission</code>
804      * for each <code>Principal</code> associated with the provided
805      * <code>Subject</code>.  Each new <code>PrivateCredentialPermission</code>
806      * contains the same Credential class as specified in the
807      * originally granted permission, as well as the Class and name
808      * for the respective <code>Principal</code>.
809      *
810      * <p>
811      *
812      * @param subject the Permissions granted to this <code>Subject</code>
813      *          and the additionally provided <code>CodeSource</code>
814      *          are returned. <p>
815      *
816      * @param codesource the Permissions granted to this <code>CodeSource</code>
817      *          and the additionally provided <code>Subject</code>
818      *          are returned.
819      *
820      * @return the Permissions granted to the provided <code>Subject</code>
821      *          <code>CodeSource</code>.
822      */
823     public PermissionCollection getPermissions(final Subject subject,
824                                         final CodeSource codesource) {
825 
826         // XXX  when JAAS goes into the JDK core,
827         //      we can remove this method and simply
828         //      rely on the getPermissions variant that takes a codesource,
829         //      which no one can use at this point in time.
830         //      at that time, we can also make SubjectCodeSource a public
831         //      class.
832 
833         // XXX
834         //
835         // 1)   if code instantiates PolicyFile directly, then it will need
836         //      all the permissions required for the PolicyFile initialization
837         // 2)   if code calls Policy.getPolicy, then it simply needs
838         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
839         //      implementation instantiates PolicyFile in a doPrivileged block
840         // 3)   if after instantiating a Policy (either via #1 or #2),
841         //      code calls getPermissions, PolicyFile wraps the call
842         //      in a doPrivileged block.
843         return java.security.AccessController.doPrivileged
844             (new java.security.PrivilegedAction<PermissionCollection>() {
845             public PermissionCollection run() {
846                 SubjectCodeSource scs = new SubjectCodeSource
847                     (subject,
848                     null,
849                     codesource == null ? null : codesource.getLocation(),
850                     codesource == null ? null : codesource.getCertificates());
851                 if (initialized)
852                     return getPermissions(new Permissions(), scs);
853                 else
854                     return new PolicyPermissions(PolicyFile.this, scs);
855             }
856         });
857     }
858 
859     /**
860      * Examines the global policy for the specified CodeSource, and
861      * creates a PermissionCollection object with
862      * the set of permissions for that principal's protection domain.
863      *
864      * @param CodeSource the codesource associated with the caller.
865      * This encapsulates the original location of the code (where the code
866      * came from) and the public key(s) of its signer.
867      *
868      * @return the set of permissions according to the policy.
869      */
870     PermissionCollection getPermissions(CodeSource codesource) {
871 
872         if (initialized)
873             return getPermissions(new Permissions(), codesource);
874         else
875             return new PolicyPermissions(this, codesource);
876     }
877 
878     /**
879      * Examines the global policy for the specified CodeSource, and
880      * creates a PermissionCollection object with
881      * the set of permissions for that principal's protection domain.
882      *
883      * @param permissions the permissions to populate
884      * @param codesource the codesource associated with the caller.
885      * This encapsulates the original location of the code (where the code
886      * came from) and the public key(s) of its signer.
887      *
888      * @return the set of permissions according to the policy.
889      */
890     Permissions getPermissions(final Permissions perms,
891                                final CodeSource cs)
892     {
893         if (!initialized) {
894             init();
895         }
896 
897         final CodeSource codesource[] = {null};
898 
899         codesource[0] = canonicalizeCodebase(cs, true);
900 
901         if (debug != null) {
902             debug.println("evaluate("+codesource[0]+")\n");
903         }
904 
905         // needs to be in a begin/endPrivileged block because
906         // codesource.implies calls URL.equals which does an
907         // InetAddress lookup
908 
909         for (int i = 0; i < policyEntries.size(); i++) {
910 
911            PolicyEntry entry = policyEntries.elementAt(i);
912 
913            if (debug != null) {
914                 debug.println("PolicyFile CodeSource implies: " +
915                         entry.codesource.toString() + "\n\n" +
916                         "\t" + codesource[0].toString() + "\n\n");
917            }
918 
919            if (entry.codesource.implies(codesource[0])) {
920                for (int j = 0; j < entry.permissions.size(); j++) {
921                     Permission p = entry.permissions.elementAt(j);
922                     if (debug != null) {
923                        debug.println("  granting " + p);
924                     }
925                     if (!addSelfPermissions(p, entry.codesource,
926                                         codesource[0], perms)) {
927                         // we could check for duplicates
928                         // before adding new permissions,
929                         // but the SubjectDomainCombiner
930                         // already checks for duplicates later
931                         perms.add(p);
932                     }
933                 }
934             }
935         }
936 
937         // now see if any of the keys are trusted ids.
938 
939         if (!ignoreIdentityScope) {
940             Certificate certs[] = codesource[0].getCertificates();
941             if (certs != null) {
942                 for (int k=0; k < certs.length; k++) {
943                     if ((aliasMapping.get(certs[k]) == null) &&
944                         checkForTrustedIdentity(certs[k])) {
945                         // checkForTrustedIdentity added it
946                         // to the policy for us. next time
947                         // around we'll find it. This time
948                         // around we need to add it.
949                         perms.add(new java.security.AllPermission());
950                     }
951                 }
952             }
953         }
954         return perms;
955     }
956 
957     /**
958      * Returns true if 'Self' permissions were added to the provided
959      * 'perms', and false otherwise.
960      *
961      * <p>
962      *
963      * @param p check to see if this Permission is a "SELF"
964      *                  PrivateCredentialPermission. <p>
965      *
966      * @param entryCs the codesource for the Policy entry.
967      *
968      * @param accCs the codesource for from the current AccessControlContext.
969      *
970      * @param perms the PermissionCollection where the individual
971      *                  PrivateCredentialPermissions will be added.
972      */
973     private boolean addSelfPermissions(final Permission p,
974                                 CodeSource entryCs,
975                                 CodeSource accCs,
976                                 Permissions perms) {
977 
978         if (!(p instanceof PrivateCredentialPermission))
979             return false;
980 
981         if (!(entryCs instanceof SubjectCodeSource))
982             return false;
983 
984 
985         PrivateCredentialPermission pcp = (PrivateCredentialPermission)p;
986         SubjectCodeSource scs = (SubjectCodeSource)entryCs;
987 
988         // see if it is a SELF permission
989         String[][] pPrincipals = pcp.getPrincipals();
990         if (pPrincipals.length <= 0 ||
991             !pPrincipals[0][0].equalsIgnoreCase("self") ||
992             !pPrincipals[0][1].equalsIgnoreCase("self")) {
993 
994             // regular PrivateCredentialPermission
995             return false;
996         } else {
997 
998             // granted a SELF permission - create a
999             // PrivateCredentialPermission for each
1000             // of the Policy entry's CodeSource Principals
1001 
1002             if (scs.getPrincipals() == null) {
1003                 // XXX SubjectCodeSource has no Subject???
1004                 return true;
1005             }
1006 
1007             ListIterator<PolicyParser.PrincipalEntry> pli =
1008                                         scs.getPrincipals().listIterator();
1009             while (pli.hasNext()) {
1010 
1011                 PolicyParser.PrincipalEntry principal = pli.next();
1012 
1013                 // XXX
1014                 //      if the Policy entry's Principal does not contain a
1015                 //              WILDCARD for the Principal name, then a
1016                 //              new PrivateCredentialPermission is created
1017                 //              for the Principal listed in the Policy entry.
1018                 //      if the Policy entry's Principal contains a WILDCARD
1019                 //              for the Principal name, then a new
1020                 //              PrivateCredentialPermission is created
1021                 //              for each Principal associated with the Subject
1022                 //              in the current ACC.
1023 
1024                 String[][] principalInfo = getPrincipalInfo
1025                                                 (principal, accCs);
1026 
1027                 for (int i = 0; i < principalInfo.length; i++) {
1028 
1029                     // here's the new PrivateCredentialPermission
1030 
1031                     PrivateCredentialPermission newPcp =
1032                         new PrivateCredentialPermission
1033                                 (pcp.getCredentialClass() +
1034                                         " " +
1035                                         principalInfo[i][0] +
1036                                         " " +
1037                                         "\"" + principalInfo[i][1] + "\"",
1038                                 "read");
1039 
1040                     if (debug != null) {
1041                         debug.println("adding SELF permission: " +
1042                                         newPcp.toString());
1043                     }
1044 
1045                     perms.add(newPcp);
1046                 }
1047             }
1048         }
1049         return true;
1050     }
1051 
1052     /**
1053      * return the principal class/name pair in the 2D array.
1054      * array[x][y]:     x corresponds to the array length.
1055      *                  if (y == 0), it's the principal class.
1056      *                  if (y == 1), it's the principal name.
1057      */
1058     private String[][] getPrincipalInfo
1059                 (PolicyParser.PrincipalEntry principal,
1060                 final CodeSource accCs) {
1061 
1062         // there are 3 possibilities:
1063         // 1) the entry's Principal class and name are not wildcarded
1064         // 2) the entry's Principal name is wildcarded only
1065         // 3) the entry's Principal class and name are wildcarded
1066 
1067         if (!principal.principalClass.equals
1068                 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1069             !principal.principalName.equals
1070                 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1071 
1072             // build a PrivateCredentialPermission for the principal
1073             // from the Policy entry
1074             String[][] info = new String[1][2];
1075             info[0][0] = principal.principalClass;
1076             info[0][1] = principal.principalName;
1077             return info;
1078 
1079         } else if (!principal.principalClass.equals
1080                 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1081             principal.principalName.equals
1082                 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1083 
1084             // build a PrivateCredentialPermission for all
1085             // the Subject's principals that are instances of principalClass
1086 
1087             // the accCs is guaranteed to be a SubjectCodeSource
1088             // because the earlier CodeSource.implies succeeded
1089             SubjectCodeSource scs = (SubjectCodeSource)accCs;
1090 
1091             Set<Principal> principalSet = null;
1092             try {
1093                 Class pClass = Class.forName(principal.principalClass, false,
1094                                 ClassLoader.getSystemClassLoader());
1095                 principalSet = scs.getSubject().getPrincipals(pClass);
1096             } catch (Exception e) {
1097                 if (debug != null) {
1098                     debug.println("problem finding Principal Class " +
1099                                 "when expanding SELF permission: " +
1100                                 e.toString());
1101                 }
1102             }
1103 
1104             if (principalSet == null) {
1105                 // error
1106                 return new String[0][0];
1107             }
1108 
1109             String[][] info = new String[principalSet.size()][2];
1110             java.util.Iterator<Principal> pIterator = principalSet.iterator();
1111 
1112             int i = 0;
1113             while (pIterator.hasNext()) {
1114                 Principal p = pIterator.next();
1115                 info[i][0] = p.getClass().getName();
1116                 info[i][1] = p.getName();
1117                 i++;
1118             }
1119             return info;
1120 
1121         } else {
1122 
1123             // build a PrivateCredentialPermission for every
1124             // one of the current Subject's principals
1125 
1126             // the accCs is guaranteed to be a SubjectCodeSource
1127             // because the earlier CodeSource.implies succeeded
1128             SubjectCodeSource scs = (SubjectCodeSource)accCs;
1129             Set<Principal> principalSet = scs.getSubject().getPrincipals();
1130 
1131             String[][] info = new String[principalSet.size()][2];
1132             java.util.Iterator<Principal> pIterator = principalSet.iterator();
1133 
1134             int i = 0;
1135             while (pIterator.hasNext()) {
1136                 Principal p = pIterator.next();
1137                 info[i][0] = p.getClass().getName();
1138                 info[i][1] = p.getName();
1139                 i++;
1140             }
1141             return info;
1142         }
1143     }
1144 
1145     /*
1146      * Returns the signer certificates from the list of certificates associated
1147      * with the given code source.
1148      *
1149      * The signer certificates are those certificates that were used to verify
1150      * signed code originating from the codesource location.
1151      *
1152      * This method assumes that in the given code source, each signer
1153      * certificate is followed by its supporting certificate chain
1154      * (which may be empty), and that the signer certificate and its
1155      * supporting certificate chain are ordered bottom-to-top (i.e., with the
1156      * signer certificate first and the (root) certificate authority last).
1157      */
1158     Certificate[] getSignerCertificates(CodeSource cs) {
1159         Certificate[] certs = null;
1160         if ((certs = cs.getCertificates()) == null)
1161             return null;
1162         for (int i=0; i<certs.length; i++) {
1163             if (!(certs[i] instanceof X509Certificate))
1164                 return cs.getCertificates();
1165         }
1166 
1167         // Do we have to do anything?
1168         int i = 0;
1169         int count = 0;
1170         while (i < certs.length) {
1171             count++;
1172             while (((i+1) < certs.length)
1173                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
1174                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
1175                 i++;
1176             }
1177             i++;
1178         }
1179         if (count == certs.length)
1180             // Done
1181             return certs;
1182 
1183         ArrayList<Certificate> userCertList = new ArrayList<>();
1184         i = 0;
1185         while (i < certs.length) {
1186             userCertList.add(certs[i]);
1187             while (((i+1) < certs.length)
1188                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
1189                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
1190                 i++;
1191             }
1192             i++;
1193         }
1194         Certificate[] userCerts = new Certificate[userCertList.size()];
1195         userCertList.toArray(userCerts);
1196         return userCerts;
1197     }
1198 
1199     private CodeSource canonicalizeCodebase(CodeSource cs,
1200                                             boolean extractSignerCerts) {
1201         CodeSource canonCs = cs;
1202         if (cs.getLocation() != null &&
1203             cs.getLocation().getProtocol().equalsIgnoreCase("file")) {
1204             try {
1205                 String path = cs.getLocation().getFile().replace
1206                                                         ('/',
1207                                                         File.separatorChar);
1208                 URL csUrl = null;
1209                 if (path.endsWith("*")) {
1210                     // remove trailing '*' because it causes canonicalization
1211                     // to fail on win32
1212                     path = path.substring(0, path.length()-1);
1213                     boolean appendFileSep = false;
1214                     if (path.endsWith(File.separator))
1215                         appendFileSep = true;
1216                     if (path.equals("")) {
1217                         path = System.getProperty("user.dir");
1218                     }
1219                     File f = new File(path);
1220                     path = f.getCanonicalPath();
1221                     StringBuffer sb = new StringBuffer(path);
1222                     // reappend '*' to canonicalized filename (note that
1223                     // canonicalization may have removed trailing file
1224                     // separator, so we have to check for that, too)
1225                     if (!path.endsWith(File.separator) &&
1226                         (appendFileSep || f.isDirectory()))
1227                         sb.append(File.separatorChar);
1228                     sb.append('*');
1229                     path = sb.toString();
1230                 } else {
1231                     path = new File(path).getCanonicalPath();
1232                 }
1233                 csUrl = new File(path).toURL();
1234 
1235                 if (cs instanceof SubjectCodeSource) {
1236                     SubjectCodeSource scs = (SubjectCodeSource)cs;
1237                     if (extractSignerCerts) {
1238                         canonCs = new SubjectCodeSource
1239                                                 (scs.getSubject(),
1240                                                 scs.getPrincipals(),
1241                                                 csUrl,
1242                                                 getSignerCertificates(scs));
1243                     } else {
1244                         canonCs = new SubjectCodeSource
1245                                                 (scs.getSubject(),
1246                                                 scs.getPrincipals(),
1247                                                 csUrl,
1248                                                 scs.getCertificates());
1249                     }
1250                 } else {
1251                     if (extractSignerCerts) {
1252                         canonCs = new CodeSource(csUrl,
1253                                                 getSignerCertificates(cs));
1254                     } else {
1255                         canonCs = new CodeSource(csUrl,
1256                                                 cs.getCertificates());
1257                     }
1258                 }
1259             } catch (IOException ioe) {
1260                 // leave codesource as it is, unless we have to extract its
1261                 // signer certificates
1262                 if (extractSignerCerts) {
1263                     if (!(cs instanceof SubjectCodeSource)) {
1264                         canonCs = new CodeSource(cs.getLocation(),
1265                                                 getSignerCertificates(cs));
1266                     } else {
1267                         SubjectCodeSource scs = (SubjectCodeSource)cs;
1268                         canonCs = new SubjectCodeSource(scs.getSubject(),
1269                                                 scs.getPrincipals(),
1270                                                 scs.getLocation(),
1271                                                 getSignerCertificates(scs));
1272                     }
1273                 }
1274             }
1275         } else {
1276             if (extractSignerCerts) {
1277                 if (!(cs instanceof SubjectCodeSource)) {
1278                     canonCs = new CodeSource(cs.getLocation(),
1279                                         getSignerCertificates(cs));
1280                 } else {
1281                     SubjectCodeSource scs = (SubjectCodeSource)cs;
1282                     canonCs = new SubjectCodeSource(scs.getSubject(),
1283                                         scs.getPrincipals(),
1284                                         scs.getLocation(),
1285                                         getSignerCertificates(scs));
1286                 }
1287             }
1288         }
1289         return canonCs;
1290     }
1291 
1292     /**
1293      * Each entry in the policy configuration file is represented by a
1294      * PolicyEntry object.  <p>
1295      *
1296      * A PolicyEntry is a (CodeSource,Permission) pair.  The
1297      * CodeSource contains the (URL, PublicKey) that together identify
1298      * where the Java bytecodes come from and who (if anyone) signed
1299      * them.  The URL could refer to localhost.  The URL could also be
1300      * null, meaning that this policy entry is given to all comers, as
1301      * long as they match the signer field.  The signer could be null,
1302      * meaning the code is not signed. <p>
1303      *
1304      * The Permission contains the (Type, Name, Action) triplet. <p>
1305      *
1306      * For now, the Policy object retrieves the public key from the
1307      * X.509 certificate on disk that corresponds to the signedBy
1308      * alias specified in the Policy config file.  For reasons of
1309      * efficiency, the Policy object keeps a hashtable of certs already
1310      * read in.  This could be replaced by a secure internal key
1311      * store.
1312      *
1313      * <p>
1314      * For example, the entry
1315      * <pre>
1316      *          permission java.io.File "/tmp", "read,write",
1317      *          signedBy "Duke";
1318      * </pre>
1319      * is represented internally
1320      * <pre>
1321      *
1322      * FilePermission f = new FilePermission("/tmp", "read,write");
1323      * PublicKey p = publickeys.get("Duke");
1324      * URL u = InetAddress.getLocalHost();
1325      * CodeBase c = new CodeBase( p, u );
1326      * pe = new PolicyEntry(f, c);
1327      * </pre>
1328      *
1329      * @author Marianne Mueller
1330      * @author Roland Schemers
1331      * @see java.security.CodeSource
1332      * @see java.security.Policy
1333      * @see java.security.Permissions
1334      * @see java.security.ProtectionDomain
1335      */
1336 
1337     private static class PolicyEntry {
1338 
1339         CodeSource codesource;
1340         Vector<Permission> permissions;
1341 
1342         /**
1343          * Given a Permission and a CodeSource, create a policy entry.
1344          *
1345          * XXX Decide if/how to add validity fields and "purpose" fields to
1346          * XXX policy entries
1347          *
1348          * @param cs the CodeSource, which encapsulates the URL and the public
1349          *        key
1350          *        attributes from the policy config file.   Validity checks are
1351          *        performed on the public key before PolicyEntry is called.
1352          *
1353          */
1354         PolicyEntry(CodeSource cs)
1355         {
1356             this.codesource = cs;
1357             this.permissions = new Vector<Permission>();
1358         }
1359 
1360         /**
1361          * add a Permission object to this entry.
1362          */
1363         void add(Permission p) {
1364             permissions.addElement(p);
1365         }
1366 
1367         /**
1368          * Return the CodeSource for this policy entry
1369          */
1370         CodeSource getCodeSource() {
1371             return this.codesource;
1372         }
1373 
1374         public String toString(){
1375             StringBuffer sb = new StringBuffer();
1376             sb.append(rb.getString("LPARAM"));
1377             sb.append(getCodeSource());
1378             sb.append("\n");
1379             for (int j = 0; j < permissions.size(); j++) {
1380                 Permission p = permissions.elementAt(j);
1381                 sb.append(rb.getString("SPACE"));
1382                 sb.append(rb.getString("SPACE"));
1383                 sb.append(p);
1384                 sb.append(rb.getString("NEWLINE"));
1385             }
1386             sb.append(rb.getString("RPARAM"));
1387             sb.append(rb.getString("NEWLINE"));
1388             return sb.toString();
1389         }
1390 
1391     }
1392 }
1393 
1394 class PolicyPermissions extends PermissionCollection {
1395 
1396     private static final long serialVersionUID = -1954188373270545523L;
1397 
1398     private CodeSource codesource;
1399     private Permissions perms;
1400     private PolicyFile policy;
1401     private boolean notInit; // have we pulled in the policy permissions yet?
1402     private Vector<Permission> additionalPerms;
1403 
1404     PolicyPermissions(PolicyFile policy,
1405                       CodeSource codesource)
1406     {
1407         this.codesource = codesource;
1408         this.policy = policy;
1409         this.perms = null;
1410         this.notInit = true;
1411         this.additionalPerms = null;
1412     }
1413 
1414     public void add(Permission permission) {
1415         if (isReadOnly())
1416             throw new SecurityException
1417             (PolicyFile.rb.getString
1418             ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection"));
1419 
1420         if (perms == null) {
1421             if (additionalPerms == null)
1422                 additionalPerms = new Vector<Permission>();
1423             additionalPerms.add(permission);
1424         } else {
1425             perms.add(permission);
1426         }
1427     }
1428 
1429     private synchronized void init() {
1430         if (notInit) {
1431             if (perms == null)
1432                 perms = new Permissions();
1433 
1434             if (additionalPerms != null) {
1435                 Enumeration<Permission> e = additionalPerms.elements();
1436                 while (e.hasMoreElements()) {
1437                     perms.add(e.nextElement());
1438                 }
1439                 additionalPerms = null;
1440             }
1441             policy.getPermissions(perms,codesource);
1442             notInit=false;
1443         }
1444     }
1445 
1446     public boolean implies(Permission permission) {
1447         if (notInit)
1448             init();
1449         return perms.implies(permission);
1450     }
1451 
1452     public Enumeration<Permission> elements() {
1453         if (notInit)
1454             init();
1455         return perms.elements();
1456     }
1457 
1458     public String toString() {
1459         if (notInit)
1460             init();
1461         return perms.toString();
1462     }
1463 }